package Time

import (
	"fmt"
	"math"
	"math/rand"
	"strings"
	"time"
)

const (
	ANSIC         = "Mon Jan _2 15:04:05 2006"
	UnixDate      = "Mon Jan _2 15:04:05 MST 2006"
	RubyDate      = "Mon Jan 02 15:04:05 -0700 2006"
	RFC822        = "02 Jan 06 15:04 MST"
	RFC822Z       = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
	RFC850        = "Monday, 02-Jan-06 15:04:05 MST"
	RFC1123       = "Mon, 02 Jan 2006 15:04:05 MST"
	RFC1123Z      = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
	RFC3339       = "2006-01-02T15:04:05Z07:00"
	RFC3339Nano   = "2006-01-02T15:04:05.999999999Z07:00"
	Kitchen       = "3:04PM"
	Stamp         = "Jan _2 15:04:05"
	StampMilli    = "Jan _2 15:04:05.000"
	StampMicro    = "Jan _2 15:04:05.000000"
	StampNano     = "Jan _2 15:04:05.000000000"
	UTFALL_SECOND = "2006-01-02 15:04:05"
	UTFALL_MINUTE = "2006-01-02 15:04"
	UTFALL_HOUR   = "2006-01-02 15"
	UTFALL_DATE   = "2006-01-02"
)

type TimeHelper struct {
	time time.Time
}

var cstZone = time.FixedZone("CST", 8*3600)

type TimeWeek struct {
	Year    int
	Month   int
	Weekday int
}

func NewTime(time time.Time) *TimeHelper {
	return &TimeHelper{time: time}
}

func (t *TimeHelper) GetYear() int {
	return t.time.Year()
}

func (t *TimeHelper) GetMonth() int {
	return int(t.time.Month())
}

func (t *TimeHelper) GetDay() int {
	return t.time.Day()
}

func (t *TimeHelper) GetHour() int {
	return t.time.Hour()
}

func (t *TimeHelper) GetMinute() int {
	return t.time.Minute()
}

func (t *TimeHelper) GetSecond() int {
	return t.time.Second()
}

func (t *TimeHelper) GetWeekDay() *TimeWeek {
	return t.WeekByDate(t.time)
}

func (t *TimeHelper) ToAll() string {
	return t.time.Format(UTFALL_SECOND)
}

func (t *TimeHelper) ToDate() string {
	return t.time.Format(UTFALL_DATE)
}

func (t *TimeHelper) WeekByDate(time time.Time) *TimeWeek {
	yearDay := time.YearDay()
	yearFirstDay := time.AddDate(0, 0, -yearDay+1)
	firstDayInWeek := int(yearFirstDay.Weekday())

	//今年第一周有几天
	firstWeekDays := 1
	if firstDayInWeek != 0 {
		firstWeekDays = 7 - firstDayInWeek + 1
	}
	var week int
	if yearDay <= firstWeekDays {
		week = 1
	} else {
		week = (yearDay-firstWeekDays)/7 + 2
	}
	weekDay := &TimeWeek{
		Year:    time.Year(),
		Month:   int(time.Month()),
		Weekday: week,
	}
	return weekDay
}

func GetNowTime() time.Time {
	return time.Now().In(cstZone)
}
func GetNowTimeStr() string {
	return NewTime(GetNowTime()).ToAll()
}

func GetArbitrarilyTimeStr(increment time.Duration) string {
	return time.Now().Add(increment).Format(UTFALL_SECOND)
}

func TimePare(timeStr string) (time.Time, error) {
	return time.ParseInLocation(UTFALL_SECOND, timeStr, cstZone)
}

/**
时间过去计算
解析字符串日期格式 ：Y-m-d H:i:s
*/
func OverFormatTime(formatTime string) string {
	if strings.Trim(formatTime, " ") == "" {
		return ""
	}
	timeLong, err := TimePare(formatTime)
	if err != nil {
		return ""
	}
	var timeOverFormat string

	nowTime := GetNowTime()
	diffTime := nowTime.Sub(timeLong).Seconds()
	if diffTime < 60 {
		timeOverFormat = "刚刚"
	} else if diffTime < 3600 {
		min := int64(math.Floor(diffTime / 60))
		timeOverFormat = fmt.Sprintf("%d分钟前", min)
	} else if diffTime < 86400 {
		min := int64(math.Floor(diffTime / 3600))
		timeOverFormat = fmt.Sprintf("%d小时前", min)
	} else if diffTime < 864003 {
		min := int64(math.Floor(diffTime / 86400))
		if min == 1 {
			timeOverFormat = "昨天"
		} else {
			timeOverFormat = "前天"
		}
	} else {
		timeOverFormat = formatTime
	}

	return timeOverFormat
}

/**
GetBetweenDates 根据开始日期和结束日期计算出时间段内所有日期
参数为日期格式，如：2020-01-01
*/
func GetBetweenDates(sdate string, edate string) []string {
	d := []string{}
	timeFormatTpl := UTFALL_SECOND
	if len(timeFormatTpl) != len(sdate) {
		timeFormatTpl = timeFormatTpl[0:len(sdate)]
	}
	date, err := time.Parse(timeFormatTpl, sdate)
	if err != nil {
		// 时间解析，异常
		return d
	}
	date2, err := time.Parse(timeFormatTpl, edate)
	if err != nil {
		// 时间解析，异常
		return d
	}
	if date2.Before(date) {
		// 如果结束时间小于开始时间，异常
		return d
	}
	// 输出日期格式固定
	timeFormatTpl = UTFALL_DATE
	date2Str := date2.Format(timeFormatTpl)
	d = append(d, date.Format(timeFormatTpl))
	for {
		date = date.AddDate(0, 0, 1)
		dateStr := date.Format(timeFormatTpl)
		d = append(d, dateStr)
		if dateStr == date2Str {
			break
		}
	}
	return d
}

/**
GetMonthStartAndEnd 获取月份的第一天和最后一天
*/
func GetMonthStartAndEnd() (string, string) {
	year, month, _ := time.Now().Date()
	thisMonth := time.Date(year, month, 1, 0, 0, 0, 0, time.Local)
	start := thisMonth.AddDate(0, 0, 0).Format(UTFALL_DATE)
	end := thisMonth.AddDate(0, 1, -1).Format(UTFALL_DATE)
	return start, end
}

/**
获取上月开始日期和结束日期
*/
func GetLastMonthStartAndEnd() (string, string) {
	year, month, _ := time.Now().Date()
	thisMonth := time.Date(year, month, 1, 0, 0, 0, 0, time.Local)
	start := thisMonth.AddDate(0, -1, 0).Format(UTFALL_DATE)
	end := thisMonth.AddDate(0, 0, -1).Format(UTFALL_DATE)
	return start, end
}

/**
获取过去7天日期
*/
func GetLastSevenDates() []string {
	var chartKey []string
	for i := 0; i < 7; i++ {
		timeStr := time.Now().AddDate(0, 0, -i).Format(UTFALL_DATE)
		chartKey = append(chartKey, timeStr)
	}
	return chartKey
}

func GetNowDayTimeStr() string {
	return time.Now().Format(UTFALL_DATE)
}

func GetNowDayTimeStrUnderline() string {
	return time.Now().Format("2006_01_02")
}

func GetLastDayTimeStrUnderline() string {
	year, month, day := time.Now().Date()
	thisMonth := time.Date(year, month, day, 0, 0, 0, 0, time.Local)
	return thisMonth.AddDate(0, 0, -1).Format("2006_01_02")
}

/**
获取昨天的日期字符串
*/
func GetYesterDayTimeStr() string {
	year, month, day := time.Now().Date()
	thisMonth := time.Date(year, month, day, 0, 0, 0, 0, time.Local)
	return thisMonth.AddDate(0, 0, -1).Format(UTFALL_DATE)
}

/**
生成unix十位的时间戳；单位秒
*/
func GetTimeUnix() int64 {
	return time.Now().Unix()
}

/**
生成UnixNano的时间戳；单位纳秒
*/
func GetTimeUnixNano() int64 {
	return time.Now().UnixNano() //单位纳秒
}

/**
生成UnixNano的时间戳；单位毫秒
*/
func GetTimeUnixHaoMiao() int64 {
	return (time.Now().UnixNano() / 1e6) //单位毫秒
}

/**
获取30天过期时间
*/
func Get30DayExpireTime() time.Duration {
	rand.Seed(time.Now().Unix())
	randNum := rand.Int31n(100)
	timeOut := time.Hour*24*30 + time.Duration(randNum)
	return timeOut
}

/**
获取七天过期时间
*/
func GetSevenExpireTime() time.Duration {
	rand.Seed(time.Now().Unix())
	randNum := rand.Int31n(100)
	timeOut := time.Hour*24*7 + time.Duration(randNum)
	return timeOut
}

/**
获取1天过期时间
*/
func GetOneDayExpireTime() time.Duration {
	rand.Seed(time.Now().Unix())
	randNum := rand.Int31n(100)
	timeOut := time.Hour*24 + time.Duration(randNum)
	return timeOut
}

/**
获取60秒随机过期时间
*/
func Get60SecondExpireTime() time.Duration {
	rand.Seed(time.Now().Unix())
	randNum := rand.Int31n(40)
	timeOut := time.Second*60 + time.Duration(randNum)
	return timeOut
}

/**
获取5分钟随机过期时间
*/
func GetFiveMinExpireTime() time.Duration {
	rand.Seed(time.Now().Unix())
	randNum := rand.Int31n(50)
	timeOut := time.Second*60*5 + time.Duration(randNum)
	return timeOut
}
